/**
 * 
 */
package gui.controller;

import engine.ExternalSource;
import engine.Service;
import gui.view.CartesianServicesTableModel;
import gui.view.EngineMain;
import gui.view.InputPanel;
import gui.view.ServicesPanel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import stubs.AttributeValueGenerator;
import stubs.ServiceStub;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * @author Elisa Costante
 * 
 */
public class ServicesPanelListener implements ActionListener {
	private ServicesPanel panel;
	private String probabilityDistribution;
	private ArrayList<ExternalSource> servicesAsSources;
	private EngineMain frame;

	public ServicesPanelListener(ServicesPanel panel) {
		super();
		this.panel = panel;
		this.frame = panel.getFrame();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equalsIgnoreCase("NumberOfServices")) {
			changeNumberOfServices(false);

		} else if (e.getActionCommand().equalsIgnoreCase("load")) {
			loadAction();

		} else if (e.getActionCommand().equalsIgnoreCase("save")) {

			saveAction();
			JOptionPane.showMessageDialog(panel, "File saved with success.");

		} else if (e.getActionCommand().equalsIgnoreCase("okInputPanel")) {

			// update the monitoredServicesList
			updateMonitoredServicesFromList(servicesAsSources);

			// Close the internal frame
			panel.closeInternalFrame();

		} else if (e.getActionCommand().equalsIgnoreCase("generate")) {

			servicesAsSources = getClonedMonitoredServices();
			AttributeValueGenerator.generateAction(servicesAsSources);
			// Update the source list
			panel.getInputPanel().refreshDataModel(servicesAsSources);

		} else if (e.getActionCommand().equalsIgnoreCase("probabilityChange")) {
			// setProbabilityDistribution();

		} else if (e.getActionCommand().equalsIgnoreCase("generateData")) {
			// Update the monitoredServices info into the main panel
			finishAction();
			// Do a clone of the monitored services list
			servicesAsSources = getClonedMonitoredServices();

			// show the panel
			InputPanel inputPanel = new InputPanel(servicesAsSources, panel
					.getFrame().getAttributeArrayList(), this);
			panel.openInternalFrame(inputPanel);

		}

	}

	/**
	 * Transform the monitoredServices as a List o ExternalSource and retruns a
	 * cloned list.
	 */
	private ArrayList<ExternalSource> getClonedMonitoredServices() {
		// show the internal frame with the generated data

		ArrayList<ExternalSource> sourceList = null;

		ArrayList<Service> monitoredServices = panel.getFrame()
				.getMonitoredServices();

		if (monitoredServices != null) {
			sourceList = new ArrayList<ExternalSource>();
			for (Service service : monitoredServices) {
				ExternalSource serviceAsSource = new ExternalSource(service
						.getIdentifierName());
				if (service.getMonitoredServices() != null) {
					ArrayList<Service> clonedMonitoredServices = new ArrayList<Service>();
					for (Service measuredService : service
							.getMonitoredServices()) {

						try {
							clonedMonitoredServices
									.add((Service) measuredService.clone());
						} catch (CloneNotSupportedException e) {
							e.printStackTrace();
						}
					}

					serviceAsSource
							.setMeasuredServices(clonedMonitoredServices);
				}

				sourceList.add(serviceAsSource);
			}
		}
		return sourceList;
	}

	/**
	 * Save the settings for the previous interactions
	 */
	private void finishAction() {

		CartesianServicesTableModel tableModel = panel.getCartesianTableModel();
		int n = frame.getMonitoredServices().size();
		// For each services Check the list of previous interactions
		for (int i = 0; i < n; i++) {

			// Caller at row i
			String callerName = (String) tableModel.getValueAt(i, 0);
			ServiceStub caller = (ServiceStub) frame
					.getMonitoredServiceFromName(callerName);

			// caller.setMonitoredServicesSize(n + 1);
			for (int j = 1; j < frame.getMonitoredServices().size() + 1; j++) {

				String trustValue = (String) tableModel.getValueAt(i, j);
				if (!trustValue.equalsIgnoreCase("NULL")) {

					// Add the calle to the list of monitored services
					String calleeName = tableModel.getColumnName(j);
					ServiceStub callee = null;
					if (caller.getMonitoredService(calleeName) != null) {
						callee = caller.getMonitoredService(calleeName);
						callee.setTrustValueFromString(trustValue);

					} else {
						callee = new ServiceStub(calleeName);
						callee.setTrustValueFromString(trustValue);
						callee.setMeasuredAttributes(panel.getFrame()
								.getAttributeArrayList());
						caller.addMonitoredService(callee);
					}

				}
				caller.setMeasuredAttributes(panel.getFrame()
						.getAttributeArrayList());
			}
		}

	}

	/**
	 * 
	 */
	private void saveAction() {
		File fileChoose = CustomizedFileChooser.getFileToSave(panel);
		if (fileChoose != null) {
			saveServicesSettingsInXMLFile(fileChoose);
		} else {
			JOptionPane.showMessageDialog(panel,
					"Save action not accomplished correctly");
		}
	}

	/**
	 * 
	 */
	private void loadAction() {
		File fileChoose = CustomizedFileChooser.getFileToOpen(panel);
		if (fileChoose != null) {
			loadServicesSettingsFromXMLFile(fileChoose);
		} else {
			JOptionPane.showMessageDialog(panel, "Load not accomplished");
		}
	}

	/**
	 * @param fileChoose
	 */
	private void saveServicesSettingsInXMLFile(File fileChoose) {
		XStream xs = new XStream();

		// Write to a file in the file system
		try {
			FileOutputStream fs = new FileOutputStream(fileChoose);
			xs.toXML(frame.getMonitoredServices(), fs);
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * @param fileChoose
	 */
	@SuppressWarnings("unchecked")
	private void loadServicesSettingsFromXMLFile(File fileChoose) {
		XStream xs = new XStream(new DomDriver());
		ArrayList<Service> monitoredServicesList = new ArrayList<Service>();

		try {
			FileInputStream fis = new FileInputStream(fileChoose);
			monitoredServicesList = (ArrayList<Service>) xs.fromXML(fis);
			// update the frame copy of servicesList
			frame.setMonitoredServices(monitoredServicesList);
			// shows the services
			changeNumberOfServices(true);

		} catch (FileNotFoundException ex) {
			ex.printStackTrace();
		}

	}

	/**
	 * Return the file choose from the user.
	 * 
	 * @return the file choose from the user
	 */

	/**
	 * Change the Cartesian Table showing an nxn matrix which is used to map the
	 * previuous interactions between services. The main diagonal will be not
	 * editable with de NULL default value.
	 * 
	 * @param fromFile
	 */
	private void changeNumberOfServices(boolean fromFile) {
		int n;
		if (fromFile) {
			// Reading from the file
			n = frame.getMonitoredServices().size();
			// panel.getNumberOfServicesCombo().setSelectedItem(n);
			if (frame.getMonitoredServices() != null && n > 0) {
				ServiceStub s = (ServiceStub) frame.getMonitoredServices().get(
						0);
				panel.getProbDistrCombo().setSelectedItem(
						s.getProbDistribution());
			}

		} else {
			n = (Integer) panel.getNumberOfServicesCombo().getSelectedItem();
			ArrayList<Service> monitoredServices = new ArrayList<Service>(n);

			// Set Services
			for (int i = 1; i < n + 1; i++) {
				ServiceStub service = new ServiceStub("Service" + i);
				// service.setProbDistribution(getProbabilityDistribution());
				monitoredServices.add(service);
			}
			frame.setMonitoredServices(monitoredServices);

		}

		// Crea una tabella cartesiana nxn
		CartesianServicesTableModel tableModel = panel.getCartesianTableModel();
		tableModel.setUpTable(n, frame, fromFile);
		tableModel.setUpComboColumn(panel.getServicesCartesianTable(), panel
				.getTrustLevelCombo());

	}

	/**
	 * Set the global field <code>probabilityDitribution</code>.
	 */
	private void setProbabilityDistribution() {
		probabilityDistribution = (String) panel.getProbDistrCombo()
				.getSelectedItem();
	}

	/**
	 * @return the probabilityDistribution
	 */
	private String getProbabilityDistribution() {
		if (this.probabilityDistribution == null) {
			setProbabilityDistribution();
		}
		return this.probabilityDistribution;
	}

	/**
	 * 
	 */
	private void updateMonitoredServicesFromList(
			ArrayList<ExternalSource> servicesAsSources) {
		if (servicesAsSources != null) {
			ArrayList<Service> monitoredServiceList = new ArrayList<Service>();
			for (ExternalSource serviceAsSource : servicesAsSources) {
				try {
					ExternalSource clonedSource = (ExternalSource) serviceAsSource
							.clone();
					Service service = new ServiceStub(clonedSource
							.getIdentifierName());
					service.setMonitoredServices(clonedSource
							.getMeasuredServices());
					monitoredServiceList.add(service);
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}

			}
			panel.getFrame().setMonitoredServices(monitoredServiceList);
		}

	}
}
